Home

Managing Resources with Tagging

Overview

I completed work focused on AWS resource tagging that was divided into two main parts:

What I Learned

Throughout, I was able to:

Environment

The environment I worked with included:

The private instances had three custom tags applied:

Throughout the Tasks portion, I logged into the CommandHost and ran commands to find and change the Version tag on all development instances. I learned how to use JMESPath syntax with the AWS CLI --query option to get formatted output. I also used pre-provided scripts to stop and restart instances tagged as part of the development environment.

Task 1: My Experience Using Tags to Manage Resources

In this first task, I logged into the CommandHost and used the AWS CLI to find resources by their tags. I then modified tag values using the CLI.

How I Found Development Instances For The Project

After logging in, I used the AWS CLI to find resources in the private subnet belonging to the ERPSystem project in the development environment. I also learned how to use the --query option for better output formatting.

First, I ran this command to find all instances tagged with Project=ERPSystem:

aws ec2 describe-instances --filter "Name=tag:Project,Values=ERPSystem"

This output was extensive, showing all parameters for the seven instances with that tag. Since there was too much information to process easily, I narrowed down the results in my next step.

I used the --query parameter to limit the output to just show instance IDs:

aws ec2 describe-instances --filter "Name=tag:Project,Values=ERPSystem" --query 'Reservations[*].Instances[*].InstanceId'

My output now showed a cleaner list of instance IDs:

[ [ "i-135b491e" ], [ "i-3e584a33" ], … ]

I learned that the --query command uses JMESPath wildcard syntax to iterate through all reservations and instances, returning just the InstanceId for each.

This was better, but I wanted to include more information. So I modified my command to include both instance ID and Availability Zone:

aws ec2 describe-instances --filter "Name=tag:Project,Values=ERPSystem" --query 'Reservations[*].Instances[*].{ID:InstanceId,AZ:Placement.AvailabilityZone}'

This returned two name/value pairs for each result. I realized this command builds on the previous one by using curly braces to query multiple properties:

object.{Alias1:PropertyName1,Alias2:PropertyName2,[…]}

I could see that my filter was working, showing only instances associated with ERPSystem. However, I still couldn't identify which specific instances were being returned. I needed to include custom tag values in my output.

To include the Project tag value, I ran:

aws ec2 describe-instances --filter "Name=tag:Project,Values=ERPSystem" --query 'Reservations[*].Instances[*].{ID:InstanceId,AZ:Placement.AvailabilityZone,Project:Tags[?Key==`Project`] | [0].Value}'

Now my output included the Project tag value:

[[{ "Project": "ERPSystem", "AZ": "us-west-2a", "ID": "i-3250b838" }], … ]

I found that I could retrieve a specific named tag value using this JMESPath query syntax:

Tags[?Key==\`Project\`] | [0].Value

This instructed JMESPath to find elements within the Tags array with a Key value of "Project". The output of that command—a single Tags element—was then piped to select the first instance of this filtered set and get its Value parameter. This result was then assigned the alias "Project".

To get an even better picture of my instances, I included Environment and Version tags in my output:

aws ec2 describe-instances --filter "Name=tag:Project,Values=ERPSystem" --query 'Reservations[*].Instances[*].{ID:InstanceId,AZ:Placement.AvailabilityZone,Project:Tags[?Key==`Project`] | [0].Value,Environment:Tags[?Key==`Environment`] | [0].Value,Version:Tags[?Key==`Version`] | [0].Value}'

The results gave me a comprehensive view of the instances in the ERPSystem project:

[[{ "Environment": "production", "Project": "ERPSystem", "Version": "1.0", "AZ": "us-west-2a", "ID": "i-3250b838" }], … ]

Finally, I added a second tag filter to see only instances in the ERPSystem project that were in the development environment:

aws ec2 describe-instances --filter "Name=tag:Project,Values=ERPSystem" "Name=tag:Environment,Values=development" --query 'Reservations[*].Instances[*].{ID:InstanceId,AZ:Placement.AvailabilityZone,Project:Tags[?Key==`Project`] | [0].Value,Environment:Tags[?Key==`Environment`] | [0].Value,Version:Tags[?Key==`Version`] | [0].Value}'

This showed me just two instances, both tagged with Project=ERPSystem and Environment=development:

[[{ "Environment": "development", "Project": "ERPSystem", "Version": "1.0", "AZ": "us-west-2a", "ID": "i-9552ba9f" }], … ]

How I Changed Version Tags for Development Instances

Next, I needed to change all Version tags on instances marked as development for the ERPSystem project. Instead of changing each instance individually, I used a Bash script for batch operations.

I opened the change-resource-tags.sh file:

nano change-resource-tags.sh

Inside, I found this script:

#!/bin/bash ids=$(aws ec2 describe-instances --filter "Name=tag:Project,Values=ERPSystem" "Name=tag:Environment,Values=development" --query 'Reservations[*].Instances[*].InstanceId' --output text) aws ec2 create-tags --resources $ids --tags 'Key=Version,Value=1.1'

I analyzed how the script worked: it first used aws ec2 describe-instances to get instance IDs for all development machines in the ERPSystem project. Then it passed those values to aws ec2 create-tags to update the Version tag to 1.1.

I noticed the first command used --output text to get results as text instead of JSON, making it easier to manipulate and pass to other commands.

I closed nano and ran the script:

./change-resource-tags.sh

To verify that my version numbers were updated correctly on development instances but not on others, I ran:

aws ec2 describe-instances --filter "Name=tag:Project,Values=ERPSystem" --query 'Reservations[*].Instances[*].{ID:InstanceId, AZ:Placement.AvailabilityZone, Project:Tags[?Key==`Project`] |[0].Value,Environment:Tags[?Key==`Environment`] | [0].Value,Version:Tags[?Key==`Version`] | [0].Value}'

The results confirmed that only development instances had their Version tags updated to 1.1, while other instances remained at 1.0.

Task 2: How I Stopped and Started Resources by Tag

In this task, I used a pre-provided script to stop and start instances tagged as development instances.

Examining the Stopinator Script

I changed to the aws-tools directory:

cd aws-tools

Then I opened the stopinator.php script to understand how it worked:

nano stopinator.php

I found that this script uses the AWS SDK for PHP to stop and restart instances based on tags. This would be useful for scenarios like shutting down development servers at night and restarting them in the morning. The script searches every AWS region for instances matching specified tags.

I noted the script's arguments:

I exited the nano editor after understanding how the script worked.

Stopping and Restarting ERPSystem Development Instances

I used the stopinator.php script to shut down and then restart the development environment for the ERPSystem project.

First, I ran the script to stop the instances:

./stopinator.php -t"Project=ERPSystem;Environment=development"

I saw output showing that two instances would be stopped in my region:

Region is us-east-1 No instances to stop in region Region is us-west-1 No instances to stop in region Region is us-west-2 Identified instance i-9552ba9f Identified instance i-d35fb7d9 Stopping all identified instances... […] No instances to stop in region Region is sa-east-1 No instances to stop in region

I then opened the EC2 console by clicking EC2 in the Services menu. In the navigation pane, I clicked Instances and verified that the two instances were stopping or had already stopped.

To restart the instances, I returned to my SSH session and ran:

./stopinator.php -t"Project=ERPSystem;Environment=development" -s

I went back to the EC2 Management Console and confirmed that the two previously stopped instances were restarting.

Task 3: Challenge - Terminating Non-Compliant Instances

In this challenge, I had to find a way to terminate instances that didn't conform to security guidelines.

Since I was already familiar with AWS, I decided to try solving this challenge myself before checking the provided solution. If you're new to AWS, you might want to review the detailed solution first.

The Challenge I Faced

Scenario: My company needed me to create automated processes to terminate instances that might allow security breaches. I had identified security risks and needed to implement efficient solutions using AWS CLI or PHP SDK.

My Task: Find all instances in the private subnet without the Environment tag and terminate them (implementing a "tag-or-terminate" policy).

I had these hints to help me:

How I Approached the Solution

I realized there were multiple ways to solve this using different programming or command-line approaches. The general solution steps I identified were:

  1. Find all instances with the Environment tag defined
  2. Compare this against all available instances to identify those missing the tag
  3. Supply the non-compliant instance IDs to AWS using either aws ec2 terminate-instances or Ec2::terminateInstances()

I decided to use the PHP script approach provided to me.

Reviewing the Tag-Or-Terminate Script

I opened the terminate-instances.php script:

nano terminate-instances.php

I examined the params block and saw it required two arguments: the current region (region) and a subnet ID (subnetid). The script used the subnet ID to determine where to look for non-compliant instances.

Looking at the first code block (with the comment "# Obtain a list of all instances with the Environment tag set"), I saw it used the describeInstances() method with a filter to find all instances having the Environment tag, regardless of value. It stored these instance IDs in a hash table.

In the second code block, I saw it examined all instances in the specified subnet and compared them to the list of tagged instances. Any instance not in the tagged list had its ID added to a list of instances to terminate.

The final section of the script used the non-compliant instance IDs as arguments to the terminateInstances method.

Setting Up My Test Environment

Before running the script, I needed to create some non-compliant instances by removing the Environment tag:

  1. I went to the EC2 Management Console and viewed my running instances
  2. I selected an instance in the private subnet
  3. On the Tags tab, I clicked Add/Edit Tags
  4. I found the Environment tag and removed it by clicking the remove icon
  5. I clicked Save and repeated this process for a second instance

Running the Script

To run the script, I needed my region and subnet ID:

In the EC2 console, I selected one of my private subnet instances. From the Description tab, I copied the Availability zone field (minus the last letter) as my region and noted the Subnet ID value.

I returned to my SSH session and ran:

./terminate-instances.php -region <region> -subnetid <subnet-id>

The output showed the script checking each instance and terminating the non-compliant ones:

Checking i-dd3a90d1 Checking i-a4248ea8 Checking i-793a9075 Checking i-a9248ea5 Checking i-aa248ea6 Checking i-da3a90d6 Checking i-a13b91ad Checking i-a23b91ae Checking i-ab248ea7 Terminating instances... Instances terminated.

I verified in the EC2 console that the instances I had removed the Environment tag from were indeed terminating. This confirmed my script worked correctly to enforce the tag compliance policy.

What I Learned

Through completing this process, I gained practical experience with:

These skills are directly applicable to real-world cloud management scenarios where proper resource tagging is essential for organization, cost allocation, security compliance, and automation.

Related Topics